package com.itheima.java.ai.langchin4j.controller;

import com.itheima.java.ai.langchin4j.assistant.XiaozhiAgent;
import com.itheima.java.ai.langchin4j.bean.ChatForm;
import com.itheima.java.ai.langchin4j.service.XiaozhiAgentService;
import com.itheima.java.ai.langchin4j.enums.PromptScenario;
import com.xiaozhi.service.RetryService;
import com.xiaozhi.component.ChatMetrics;
import com.xiaozhi.component.StructuredLogger;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

@Tag(name = "小智")
@RestController
@RequestMapping("/api/xiaozhi")
@Slf4j
public class XiaozhiController {
    
    @Autowired
    private XiaozhiAgent xiaozhiAgent;
    
    @Autowired
    private XiaozhiAgentService xiaozhiAgentService;
    
    @Autowired
    private RetryService retryService;
    
    @Autowired
    private ChatMetrics chatMetrics;
    
    @Autowired
    private StructuredLogger structuredLogger;
    
    @Operation(summary = "对话")
    @PostMapping(value = "/chat", produces = MediaType.TEXT_PLAIN_VALUE)
    public ResponseBodyEmitter chat(@RequestBody ChatForm chatForm) {
        // 输入验证
        if (chatForm == null || chatForm.getMessage() == null || chatForm.getMessage().trim().isEmpty()) {
            log.warn("收到无效的聊天请求: {}", chatForm);
            ResponseBodyEmitter emitter = new ResponseBodyEmitter();
            CompletableFuture.runAsync(() -> {
                try {
                    // 使用明确的错误前缀，便于前端识别
                    emitter.send("[ERROR] 请求格式有误：请输入有效的消息内容。");
                    emitter.complete();
                } catch (IOException e) {
                    emitter.completeWithError(e);
                }
            });
            return emitter;
        }
        
        ResponseBodyEmitter emitter = new ResponseBodyEmitter(60000L); // 60秒超时
        
        // 异步处理聊天请求
        CompletableFuture.runAsync(() -> {
            long startTime = chatMetrics.recordRequestStart();
            int retryCount = 0;
            String sessionId = structuredLogger.generateSessionId();
            
            try {
                // 使用内存ID，如果没有则使用默认值
                Long memoryId = chatForm.getMemoryId() != null ? chatForm.getMemoryId() : 1L;
                
                // 记录结构化日志 - 请求开始
                structuredLogger.logChatRequestStart(sessionId, memoryId, 
                    chatForm.getMessage(), chatForm.getMessage().length());
                
                log.info("收到聊天请求，会话ID: {}, 用户消息: {}", sessionId, chatForm.getMessage());
                
                // 使用重试机制调用DeepSeek模型生成AI回复（支持动态提示词）
                CompletableFuture<String> aiResponseFuture = retryService.executeWithRetryAsync(
                    () -> xiaozhiAgentService.chat(memoryId, chatForm.getMessage()),
                    "DeepSeek聊天请求"
                );
                
                String response = aiResponseFuture.get(45, TimeUnit.SECONDS); // 增加超时时间以适应重试
                
                if (response == null || response.trim().isEmpty()) {
                    log.warn("AI返回空响应");
                    emitter.send("抱歉，我暂时无法理解您的问题，请换个方式提问。");
                    emitter.complete();
                    return;
                }
                
                log.info("AI回复生成成功，长度: {} 字符", response.length());
                
                // 流式输出，逐字符发送
                for (int i = 0; i < response.length(); i++) {
                    char c = response.charAt(i);
                    emitter.send(String.valueOf(c));
                    
                    // 模拟打字效果，添加延迟
                    Thread.sleep(50);
                }
                
                // 完成响应
                emitter.complete();
                log.info("聊天响应发送完成");
                
                // 记录成功指标和结构化日志
                long responseTime = System.currentTimeMillis() - startTime;
                chatMetrics.recordRequestSuccess(startTime, retryCount);
                structuredLogger.logChatRequestSuccess(sessionId, memoryId, 
                    responseTime, response.length(), retryCount);
                
            } catch (TimeoutException e) {
                long responseTime = System.currentTimeMillis() - startTime;
                log.error("AI响应超时，会话ID: {}: {}", sessionId, e.getMessage());
                chatMetrics.recordRequestFailure(startTime, "TIMEOUT", retryCount);
                structuredLogger.logChatRequestFailure(sessionId, 
                    chatForm.getMemoryId() != null ? chatForm.getMemoryId() : 1L, 
                    "TIMEOUT", e.getMessage(), responseTime, retryCount);
                handleError(emitter, "响应超时，请稍后重试。");
            } catch (IllegalArgumentException e) {
                long responseTime = System.currentTimeMillis() - startTime;
                log.error("请求参数错误，会话ID: {}: {}", sessionId, e.getMessage());
                chatMetrics.recordRequestFailure(startTime, "INVALID_ARGUMENT", retryCount);
                structuredLogger.logChatRequestFailure(sessionId, 
                    chatForm.getMemoryId() != null ? chatForm.getMemoryId() : 1L, 
                    "INVALID_ARGUMENT", e.getMessage(), responseTime, retryCount);
                handleError(emitter, "请求格式有误，请检查输入内容。");
            } catch (Exception e) {
                long responseTime = System.currentTimeMillis() - startTime;
                log.error("聊天处理失败，会话ID: {}: {}", sessionId, e.getMessage(), e);
                
                // 记录失败指标和结构化日志
                String errorType = getErrorType(e);
                chatMetrics.recordRequestFailure(startTime, errorType, retryCount);
                structuredLogger.logChatRequestFailure(sessionId, 
                    chatForm.getMemoryId() != null ? chatForm.getMemoryId() : 1L, 
                    errorType, e.getMessage(), responseTime, retryCount);
                
                // 根据异常类型提供不同的错误消息
                String errorMessage = getErrorMessage(e);
                handleError(emitter, errorMessage);
            }
        });
        
        return emitter;
    }
    
    /**
     * 处理错误响应
     */
    private void handleError(ResponseBodyEmitter emitter, String errorMessage) {
        try {
            emitter.send(errorMessage);
            emitter.complete();
        } catch (IOException ioException) {
            log.error("发送错误消息失败: {}", ioException.getMessage());
            emitter.completeWithError(ioException);
        }
    }
    
    /**
     * 根据异常类型获取错误类型标识
     */
    private String getErrorType(Exception e) {
        String message = e.getMessage();
        
        if (message != null) {
            String lowerMessage = message.toLowerCase();
            
            if (lowerMessage.contains("api key") || lowerMessage.contains("authentication")) {
                return "API_KEY_ERROR";
            } else if (lowerMessage.contains("network") || lowerMessage.contains("connection")) {
                return "NETWORK_ERROR";
            } else if (lowerMessage.contains("rate limit") || lowerMessage.contains("quota")) {
                return "RATE_LIMIT";
            } else if (lowerMessage.contains("timeout")) {
                return "TIMEOUT";
            } else if (lowerMessage.contains("500") || lowerMessage.contains("502") || 
                      lowerMessage.contains("503") || lowerMessage.contains("504")) {
                return "SERVER_ERROR";
            }
        }
        
        return "UNKNOWN_ERROR";
    }
    
    /**
     * 根据异常类型获取用户友好的错误消息
     */
    private String getErrorMessage(Exception e) {
        String message = e.getMessage();
        
        if (message != null) {
            if (message.contains("API key") || message.contains("authentication")) {
                return "服务配置异常，请联系管理员。";
            } else if (message.contains("network") || message.contains("connection")) {
                return "网络连接异常，请检查网络后重试。";
            } else if (message.contains("rate limit") || message.contains("quota")) {
                return "服务繁忙，请稍后重试。";
            }
        }
        
        return "抱歉，我暂时无法回复您的消息，请稍后再试。";
    }
    
    /**
     * 手动指定场景进行对话
     * 用于测试不同场景的提示词效果
     */
    @Operation(summary = "指定场景对话")
    @PostMapping(value = "/chat/scenario", produces = MediaType.TEXT_PLAIN_VALUE)
    public ResponseBodyEmitter chatWithScenario(@RequestBody ChatWithScenarioForm chatForm) {
        // 输入验证
        if (chatForm == null || chatForm.getMessage() == null || chatForm.getMessage().trim().isEmpty()) {
            log.warn("收到无效的场景聊天请求: {}", chatForm);
            ResponseBodyEmitter emitter = new ResponseBodyEmitter();
            CompletableFuture.runAsync(() -> {
                try {
                    emitter.send("[ERROR] 请求格式有误：请输入有效的消息内容。");
                    emitter.complete();
                } catch (IOException e) {
                    emitter.completeWithError(e);
                }
            });
            return emitter;
        }
        
        if (chatForm.getScenario() == null) {
            log.warn("收到无效的场景聊天请求，场景为空: {}", chatForm);
            ResponseBodyEmitter emitter = new ResponseBodyEmitter();
            CompletableFuture.runAsync(() -> {
                try {
                    emitter.send("[ERROR] 请求格式有误：请指定有效的场景。");
                    emitter.complete();
                } catch (IOException e) {
                    emitter.completeWithError(e);
                }
            });
            return emitter;
        }
        
        ResponseBodyEmitter emitter = new ResponseBodyEmitter(60000L);
        
        CompletableFuture.runAsync(() -> {
            long startTime = chatMetrics.recordRequestStart();
            int retryCount = 0;
            String sessionId = structuredLogger.generateSessionId();
            
            try {
                Long memoryId = chatForm.getMemoryId() != null ? chatForm.getMemoryId() : 1L;
                
                structuredLogger.logChatRequestStart(sessionId, memoryId, 
                    chatForm.getMessage(), chatForm.getMessage().length());
                
                log.info("收到场景聊天请求，会话ID: {}, 场景: {}, 用户消息: {}", 
                    sessionId, chatForm.getScenario().getDescription(), chatForm.getMessage());
                
                // 使用指定场景进行对话
                CompletableFuture<String> aiResponseFuture = retryService.executeWithRetryAsync(
                    () -> xiaozhiAgentService.chatWithScenario(memoryId, chatForm.getMessage(), chatForm.getScenario()),
                    "DeepSeek场景聊天请求"
                );
                
                String response = aiResponseFuture.get(45, TimeUnit.SECONDS);
                
                if (response == null || response.trim().isEmpty()) {
                    log.warn("AI返回空响应");
                    emitter.send("抱歉，我暂时无法理解您的问题，请换个方式提问。");
                    emitter.complete();
                    return;
                }
                
                log.info("AI场景回复生成成功，场景: {}, 长度: {} 字符", 
                    chatForm.getScenario().getDescription(), response.length());
                
                // 流式输出
                for (int i = 0; i < response.length(); i++) {
                    char c = response.charAt(i);
                    emitter.send(String.valueOf(c));
                    Thread.sleep(50);
                }
                
                emitter.complete();
                log.info("场景聊天响应发送完成");
                
                long responseTime = System.currentTimeMillis() - startTime;
                chatMetrics.recordRequestSuccess(startTime, retryCount);
                structuredLogger.logChatRequestSuccess(sessionId, memoryId, 
                    responseTime, response.length(), retryCount);
                
            } catch (Exception e) {
                long responseTime = System.currentTimeMillis() - startTime;
                log.error("场景聊天处理失败，会话ID: {}: {}", sessionId, e.getMessage(), e);
                
                String errorType = getErrorType(e);
                chatMetrics.recordRequestFailure(startTime, errorType, retryCount);
                structuredLogger.logChatRequestFailure(sessionId, 
                    chatForm.getMemoryId() != null ? chatForm.getMemoryId() : 1L, 
                    errorType, e.getMessage(), responseTime, retryCount);
                
                String errorMessage = getErrorMessage(e);
                handleError(emitter, errorMessage);
            }
        });
        
        return emitter;
    }
    
    /**
     * 获取可用的场景列表
     */
    @Operation(summary = "获取可用场景列表")
    @GetMapping("/scenarios")
    public ResponseEntity<PromptScenario[]> getAvailableScenarios() {
        try {
            PromptScenario[] scenarios = xiaozhiAgentService.getAvailableScenarios();
            return ResponseEntity.ok(scenarios);
        } catch (Exception e) {
            log.error("获取场景列表失败: {}", e.getMessage(), e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }
    
    /**
     * 场景聊天请求表单
     */
    public static class ChatWithScenarioForm {
        private String message;
        private Long memoryId;
        private PromptScenario scenario;
        
        public String getMessage() {
            return message;
        }
        
        public void setMessage(String message) {
            this.message = message;
        }
        
        public Long getMemoryId() {
            return memoryId;
        }
        
        public void setMemoryId(Long memoryId) {
            this.memoryId = memoryId;
        }
        
        public PromptScenario getScenario() {
            return scenario;
        }
        
        public void setScenario(PromptScenario scenario) {
            this.scenario = scenario;
        }
        
        @Override
        public String toString() {
            return "ChatWithScenarioForm{" +
                    "message='" + message + '\'' +
                    ", memoryId=" + memoryId +
                    ", scenario=" + scenario +
                    '}';
        }
    }
}
